
import 'dart:convert';
import 'dart:io';

import 'package:ceramics/model/ab_block.dart';
import 'package:ceramics/model/ab_coin.dart';
import 'package:ceramics/model/ab_config.dart';
import 'package:ceramics/model/ab_oauth.dart';
import 'package:ceramics/model/ab_order.dart';
import 'package:ceramics/model/ab_oss_policy.dart';
import 'package:ceramics/model/ab_oss_upload_res.dart';
import 'package:ceramics/model/ab_singleton.dart';
import 'package:ceramics/pages/login/ab_login_page.dart';
import 'package:ceramics/pages/main/home/ab_home_page.dart';
import 'package:ceramics/pages/main/hot/ab_hot_page.dart';
import 'package:ceramics/pages/main/video/ab_video_home_page.dart';
import 'package:ceramics/util/ab_const_url.dart';
import 'package:ceramics/util/ab_uuid.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart' show Dio, Headers, HttpClientAdapter, MultipartFile, Options, FormData;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_translate/components/google_translate.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:get/get.dart' hide MultipartFile, FormData;
import 'package:shared_preferences/shared_preferences.dart';
import 'ab_loading.dart';
import 'ab_value_converter.dart';
import 'empty.dart';


var api = ABApi();

class ABApi {
  var dio = Dio();
  final bool isTest;
  String baseURL;
  // Api({this.baseURL = "http://192.168.31.26:8000"}) {
  //   dio.options.baseUrl = baseURL;
  // }

  // Api({this.baseURL = "https://api.heyzvc.com"}) {
  //   dio.options.baseUrl = baseURL;
  // }

  ABApi({this.baseURL = ABURLs.baseURL,this.isTest = false}) {
    dio.options.baseUrl = baseURL;
  }
  Future<APIResponse?> post(String path, {dynamic parameter, bool? showLoading, Options? options}) async {
    return request(path, "POST", parameter: parameter, showLoading: showLoading, options: options);
  }

  Future<APIResponse?> get(String path, {dynamic parameter, bool? showLoading, Options? options}) async {
    return request(path, "GET", parameter: parameter, showLoading: showLoading);
  }

  Future<APIResponse?> request(String path, String method, {dynamic parameter, bool? showLoading, Options? options}) async {
    showLoading ??= isTest ? false : true;
    if (showLoading) {
      loading();
    }
    try {
      var op = options ?? Options(method: method);
      op.method = method;
      var headerMap = <String,dynamic>{};
      headerMap["device-id"] = await getUUID();
      DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
      PackageInfo packageInfo = await PackageInfo.fromPlatform();
      if (Platform.isAndroid) {
        headerMap['platform']  = 'Android';
        headerMap['model'] = await deviceInfo.androidInfo.then((value) => value.model);
        headerMap['sys_lan'] = await deviceInfo.androidInfo.then((value) => value.device);
      } else if (Platform.isIOS) {
        headerMap["platform"]  = "iOS";
        var iosInfo = await deviceInfo.iosInfo;
        headerMap["model"] = iosInfo.model;
        headerMap['sys_lan'] = iosInfo.localizedModel;
        headerMap['lang'] = iosInfo.localizedModel;
      }
      headerMap['pkg'] = packageInfo.packageName;
      headerMap['ver'] = packageInfo.version;
      headerMap['p_ver'] = packageInfo.buildNumber;
      if (!isNullOrEmpty(ABSingleton.token)) {
        headerMap['Authorization'] = 'Bearer ${ABSingleton.token}';
      }

      headerMap['kst'] = '1';
      op.headers = headerMap;

      var response = await dio.request(path, data: parameter,options: op);
      if (showLoading) {
        dismissLoading();
      }
      var data = response.data;
      if (data.runtimeType == String) {
        data = jsonDecode(data);
      }
      APIResponse apiResponse = APIResponse(valueToInt(data["code"]), valueToString(data["msg"]), data["data"]);
      if (apiResponse.code != 200 && apiResponse.code != 0) {
        if (apiResponse.code == 10010303) {
          var sp = await SharedPreferences.getInstance();
          var type = sp.getInt('loginType');
          var token = sp.getString('token');
          if (type != null && token != null) {
            var oauthResponse = await oauth(type, token);
            ABSingleton().oauth = oauthResponse;
            ABSingleton.saveOAuth();
            return request(path, method, parameter: parameter, showLoading: showLoading, options: options);
          } else {
            Get.offAll(()=>const ABLoginPage());
          }
        }
        if(showLoading) {
          toast(apiResponse.msg);
        }
      }
      return apiResponse;
    } catch (e) {
      var eStr = e.toString();
      if (e.toString().length > 40) {
        eStr = 'request error';
      }
      if (showLoading){toast(eStr);}
      rethrow;
    }
  }


  /// `oauth` 方法用于进行授权操作。
  ///
  /// 参数 `type` 用于指定授权类型，苹果登录传3，快速登录传入4。
  /// 参数 `token` 用于传递授权凭证，具体如下：
  /// - 若 `type` 为3，即苹果登录，则 `token` 传入 `credential.identityToken`。
  /// - 若 `type` 为4，即快速登录，则 `token` 传入设备id。如无法获取设备id，则传入UDID并配合keyChain做持久化存储。
  Future<ABOAuthResponse> oauth(int type, String token) async {
    var data = {
      'oauthType': type,
      'token': token,
    };

    var options = Options(
      contentType: Headers.formUrlEncodedContentType,
      method: 'POST',
    );
    var sp = await SharedPreferences.getInstance();
    await sp.setInt('loginType', type);
    await sp.setString('token', token);
    var response = await post(ABURLs.oauthURL, parameter: data, options: options);
    var oauthResponse = ABOAuthResponse.fromJson(response!.data);
    return oauthResponse;
  }

  /// 全部用户
  Future<List<ABUser>> allUsers() async {
    var response = await post(ABURLs.users, parameter: {'limit':40,
      'isPageMode': true,
      'page': 1,
    },showLoading: false);
    var userMaps = response!.data as List<dynamic>;
    var users = userMaps.map((userMap) => ABUser.fromJson(userMap)).toList();
    return users;
  }

  /// 获取ossURL
  Future<List<OSSResponse>> fetchOssURL(List<OSSRequest> medias) async {
    var data = medias.map((media) => media.toJson()).toList();
    var resList = await post(ABURLs.ossURL, parameter: data, showLoading: false);
    var ossList = resList!.data as List<dynamic>;
    var ossResponses = ossList.map((oss) => OSSResponse.fromJson(oss)).toList();
    return ossResponses;
  }

  /// 关注
  Future<void> follow(String userId) async {
    await post(ABURLs.followURL, parameter: {'followUserId': userId});
    Future.delayed(const Duration(milliseconds: 1000)).then((value) =>
        toast('Follow successful')
    );
  }

  /// 取消关注
  Future<void> unfollow(String userId) async {
    await post(ABURLs.unfollowURL, parameter: {'followUserId': userId});
    toast('Unfollow successful');
  }

  /// 获取关注列表
  Future<List<ABUser>> followList(int limit, int page) async {
    var response = await post(ABURLs.followListURL, parameter: {'limit': limit, 'page': page});
    var userMaps = response!.data as List<dynamic>;
    var users = userMaps.map((userMap) => ABUser.fromJson(userMap)).toList();
    ABSingleton.follows.value = users;
    return users;
  }

  /// 获取配置
  Future<List<ABConfig>> fetchConfig() async {
    var response = await get(ABURLs.configURL, showLoading: false);
    var aMap = response!.data as Map<String, dynamic>;
    var list = aMap['items'] as List<dynamic>;
    ABConfig.allConfig = list.map((e) => ABConfig.fromJson(e)).toList();
    // var locale = Localizations.localeOf(Get.context!).languageCode;
    var locale = Get.deviceLocale?.languageCode ?? 'en';
    GoogleTranslate.initialize(apiKey: ABConfig.googleKey, targetLanguage: locale);
    return ABConfig.allConfig;
  }

  /// 举报/拉黑
  /// 拉黑：Block 举报：Report
  /// 子项：Pornographic, False gender, Fraud, Political sensitive, Other
  Future<void> reportComplaintRecord(String userId, String category,{String? subCategory}) async {
    /// 取消关注
    await unfollow(userId);
    await post(ABURLs.reportComplaintRecordURL, parameter: {
      'broadcasterId': userId,
      'complainCategory': category,
      'complainSub': subCategory,
    });
    if (category == 'Block') {
      Future.wait([
      Get.find<ABHomeController>().loadData(),
      Get.find<ABHotController>().loadData(),
      Get.find<ABVideoHomePageController>().initAllVideos()
      ]);
    }
    toast('Report successful');
  }

  /// 黑名单列表
  Future<List<ABBlock>> blockList({bool loading = true}) {
    return post(ABURLs.blockListURL,showLoading: loading).then((response) {
      var aList = response!.data as List;
      ABSingleton.blocks.value = aList.map((e) => ABBlock.fromJson(e)).toList();
      return ABSingleton.blocks;
    });
  }

  /// 移除黑名单
  Future<void> removeBlock(String userId) async {
    await post(ABURLs.removeBlockURL, parameter: {'blockUserId': userId});
    Get.find<ABHomeController>().loadData();
    Get.find<ABHotController>().loadData();
    Get.find<ABVideoHomePageController>().initAllVideos();
  }

  /// 搜索商品
  Future<List<ABCoin>> searchGoods() async {
    var res = await post(ABURLs.searchGoods,parameter: {'isIncludeSubscription':false,'payChannel':'IAP'});
    var goods = res!.data as List;
    return goods.map((e) => ABCoin.fromJson(e)).toList();
  }

  /// 创建商品订单
  Future<ABOrder> createGoodsOrder(String goodsId) async {
    var res = await post(ABURLs.createGoodsOrder,parameter: {'goodsCode':goodsId,
      'payChannel':'IAP',
    });
    var order = ABOrder.fromJson(res!.data);
    return order;
  }

  /// 验单
  Future<void> verifyPurchase(String receipt, String? transactionId) async {
    var orderNo = (await SharedPreferences.getInstance()).getString('orderNo');
    var res = await post(ABURLs.verifyPurchase,parameter: {'transactionId':transactionId,
      'payload':receipt,
      'orderNo':orderNo
    });
  }

  /// 获取用户信息
  Future<ABUser> fetchUserInfo(String userId) async {
    var res = await post(ABURLs.userInfo,parameter: {'userId':userId});
    var user = ABUser.fromJson(res!.data);
    return user;
  }

  /// 获取当前用户信息
  Future<ABUser> fetchCurrentUser() async {
    var res = await post(ABURLs.userInfo,parameter: {'userId':ABSingleton.user?.userId});
    var user = ABUser.fromJson(res!.data);
    ABSingleton().oauth?.userInfo.copyWith(user);
    return user;
  }

  /// 保存用户信息
  Future<void> saveUserInfo({String? nickname, String? birthday, String? country}) async {
    var user = ABSingleton().oauth?.userInfo;
    await post(ABURLs.saveUserInfoURL,parameter: {'nickname':nickname,
      'birthday':birthday,
      'country':country,
    });

    if (nickname != null) {
      user?.nickname = nickname;
    }
    if (birthday != null) {
      user?.birthday = birthday;
    }
    if (country != null) {
      user?.country = country;
    }
    ABSingleton.saveOAuth();
  }

  /// 退出登录
  Future<void> logout() async {
    await post(ABURLs.logoutURL);
  }

  /// 删除账户
  Future<void> deleteAccount() async {
    await post(ABURLs.deleteAccountURL);
  }

  /// 更新头像
  Future<void>updateAvatar(String path) async {
    var res = await uploadSingleImage(path);
    var fileName = res.filename;
    await post(ABURLs.updateAvatarURL,parameter: {'avatarPath':fileName});
    var user = ABSingleton().oauth?.userInfo;
    if (fileName != null) {
      user?.avatar = fileName;
      ABSingleton.saveOAuth();
    }
  }

  /// 获取可用金币
  Future<int> fetchCoin() async {
    var res = await get(ABURLs.coinURL);
    var aMap = res!.data as Map<String, dynamic>;
    var coin = aMap['availableCoins'] as int;
    ABSingleton().oauth?.userInfo.availableCoins.value = coin;
    return coin;
  }

  /// 消耗金币
  Future<void> consumeCoin(int coin) async {
    await post(ABURLs.consumeCoinURL,parameter: {'outlay':coin,'source':'gift'});
    var user = ABSingleton().oauth?.userInfo;
    user?.availableCoins.value -= coin;
    ABSingleton.saveOAuth();
  }

  /// 用户策略
  Future<ABOSSPolicy> fetchUserPolicy() async {
    var res = await get(ABURLs.userPolicyURL);
    var aMap = res!.data as Map<String, dynamic>;
    var policy = ABOSSPolicy.fromJson(aMap);
    return policy;
    // var policy = aMap['policy'] as String;
    // ABSingleton().oauth?.userInfo.policy.value = policy;
  }

  Future<List<ABOSSUploadRes>> uploadImages(List<String> images) async {
    var policy = await fetchUserPolicy();
    return Future.wait(images.map((image) => uploadSingleImage(image,policy: policy)));
  }

  Future<ABOSSUploadRes> uploadSingleImage(String image,{ABOSSPolicy? policy}) async {
    policy ??= await fetchUserPolicy();
    var file = MultipartFile.fromFileSync(image);
    final formData = FormData.fromMap({
      'key': policy.dir + (file.filename ?? 'file'),
      'policy': policy.policy,
      'OSSAccessKeyId': policy.accessKeyId,
      'signature': policy.signature,
      'expire': policy.expire,
      'callback': policy.callback,
      'file': file,
    });
    var op = Options(
      contentType: Headers.formUrlEncodedContentType,
      method: 'POST',
    );
    var res = await post(policy.host,parameter: formData,options: op);
    var data = res!.data;
    var obj = ABOSSUploadRes.fromJson(data);
    return obj;
  }

}

class OSSRequest {
  String mediaPath;
  String mediaType;
  OSSRequest(this.mediaPath, this.mediaType);
  Map toJson() {
    return {
      'mediaPath': mediaPath,
      'mediaType': mediaType,
    };
  }
}

class OSSResponse {
  String mediaType;
  String mediaPath;
  String thumbUrl;
  String middleThumbUrl;
  String mediaUrl;
  OSSResponse(this.mediaType, this.mediaPath, this.thumbUrl, this.middleThumbUrl, this.mediaUrl);

  static OSSResponse fromJson(Map<String,dynamic> json) {
    return OSSResponse(
      valueToString(json['mediaType']),
      valueToString(json['mediaPath']),
      valueToString(json['thumbUrl']),
      valueToString(json['middleThumbUrl']),
      valueToString(json['mediaUrl']),
    );
  }

  Map<String,dynamic> toJson() {
    return {
      'mediaType': mediaType,
      'mediaPath': mediaPath,
      'thumbUrl': thumbUrl,
      'middleThumbUrl': middleThumbUrl,
      'mediaUrl': mediaUrl,
    };
  }
}

class APIResponse {
  int code;
  String msg;
  dynamic data;
  APIResponse(this.code, this.msg, this.data);
}